

(function () {
    "use strict";
    const Cu = Components.utils;
    function require(url) {
        let scope = {};
        Cu.import(url, scope);
        return scope;
    }
    let {MiscUtils} = require("chrome://jsm/content/utils.js");
    let {Services} = require("resource://gre/modules/Services.jsm");
    let {Storage} = require("chrome://jsm/content/Storage.js");
    let {DeferredTask} = require("resource://gre/modules/DeferredTask.jsm");
    let {console} = require("resource://gre/modules/devtools/Console.jsm");

    let obj = {state: "idle", actions: []};

    obj.hookDialogs = function() {
        Services.obs.addObserver(this, "tabmodal-dialog-loaded", false);
        Services.obs.addObserver(this, "common-dialog-loaded", false);
    };

    obj.unhookDialogs = function() {
        Services.obs.removeObserver(this, "tabmodal-dialog-loaded", false);
        Services.obs.removeObserver(this, "common-dialog-loaded", false);
    };

    obj.init = function() {
        ["terminate", "state-changed", "add-dialog-action"].forEach(
            topic => addMessageListener("imacros:"+topic, this)
        );
        this.hookDialogs();
    };

    obj.terminate = function() {
        ["terminate", "state-changed", "add-dialog-action"].forEach(
            topic => removeMessageListener("imacros:"+topic, this)
        );
        this.unhookDialogs();
        if (this.deferred_complete) {
            this.deferred_complete.disarm();
            this.deferred_complete = null;
        }
            
    };

    obj.receiveMessage = function(msg) {
        
        let topic = msg.name.replace(/^imacros:/, "");
        switch(topic) {
        case "state-changed":
            
            
            this.state = msg.data.state;
            return;
        case "add-dialog-action":
            
            
            
            
            this.actions.push(msg.data.action);
            return;
        case "terminate":
            this.terminate();
            return;
        }
    };

    
    obj.showMessage = function (message) {
        let doc = !this.tabmodal ? this.dlg.ui.prompt.document :
            this.dlg.ui.prompt.ownerDocument;
        this.msg = {};
        this.msg.hbox = doc.createElement("hbox");
        var hbox_label = doc.createElement("hbox");
        var hbox_image = doc.createElement("hbox");
        var label = doc.createElement("label");
        var image = doc.createElement("image");

        this.msg.hbox.setAttribute("id", "imacros-commdlg-message");
        this.msg.hbox.setAttribute("align", "center");
        this.msg.hbox.appendChild(hbox_label);
        this.msg.hbox.appendChild(image);
        hbox_label.setAttribute("pack", "center");
        hbox_label.setAttribute("flex", "1");
        hbox_label.appendChild(label);
        label.setAttribute("value", message);
        image.setAttribute("id", "imacros-commdlg-image");
        var el = this.tabmodal ? this.dlg.ui.prompt :
            this.dlg.ui.prompt.document.documentElement;
        el.insertBefore(this.msg.hbox, el.firstChild);
    };


    obj.onAccept = function() {
        this.result.accept = true;
        console.log("onAccept %O", this.result);
        sendAsyncMessage("imacros:dlg-hook", this.result);
    };


    obj.onCancel = function() {
        this.result.accept = false;
        sendAsyncMessage("imacros:dlg-hook", this.result);
    };


    obj.recordDialog = function() {
        this.result = new Object();
        this.result.type = this.promptType;
        this.showMessage(MiscUtils.strings("imacrosrecordingdialog"));
        if (this.promptType == "prompt" || this.promptType == "login") {
            this.result.val1 = this.dlg.ui.loginTextbox.value;
            this.dlg.ui.loginTextbox.addEventListener("input", () => {
                this.result.val1 = this.dlg.ui.loginTextbox.value;
            });
        }
        if (this.promptType == "login") {
            this.result.val2 = this.dlg.ui.password1Textbox.value;
            this.dlg.ui.password1Textbox.addEventListener("input", () => {
                this.result.val2 = this.dlg.ui.password1Textbox.value;
            });
        }
        console.log("recordDialog, addEventListener");
        this.dlg.ui.button0.addEventListener(
            "command", () => this.onAccept(), true
        );
        this.dlg.ui.button1.addEventListener(
            "command", () => this.onCancel(), true
        );
        this.dlg.ui.password1Textbox.addEventListener("keydown", e => {
            if (e.keyCode != 13 && e.keyCode != 14)
                return;
            this.onAccept();
        }, false);
    };


    obj.replayDialog = function() {
        
        if (!this.actions.length || !(this.action = this.actions.shift())) {
            
            let e = {
                message: "Unhandled "+this.promptType+" dialog detected."+
                    " Dialog message: \""+this.dlg.args.text+"\"",
                errnum: -1450
            };
            sendAsyncMessage("imacros:dlg-hook-error", e);
            this.completeDialog();
            return;
        } else {
            this.showMessage(MiscUtils.strings("imacrosreplayingdialog"));

            switch (this.promptType) {
            case "alert": case "confirm":
                break;
            case "prompt":
                if (this.action.content)
                    this.dlg.ui.loginTextbox.value = this.action.content;
                break;
            case "login":
                this.dlg.ui.loginTextbox.value = this.action.username;
                this.dlg.ui.password1Textbox.value = this.action.password;
                break;
            default:
            }
        }

        this.deferred_complete = new DeferredTask(() => {
            this.completeDialog();
            this.deferred_complete = null;
        }, this.action ? this.action.timeout : 0);
        this.deferred_complete.arm();
    };


    obj.completeDialog = function() {
        
        if (this.msg && this.msg.hbox) {
            let el = this.tabmodal ? this.dlg.ui.prompt :
                this.dlg.ui.prompt.document.documentElement;
            el.removeChild(this.msg.hbox);
            this.msg = null;
        }

        let ok = (function() {
            if (this.tabmodal) {
                this.dlg.ui.prompt.onButtonClick(0);
            } else {
                this.dlg.ui.prompt.document.
                    documentElement.acceptDialog();
            }
        }).bind(this);

        let cancel = (function() {
            if (this.tabmodal) {
                this.dlg.ui.prompt.onButtonClick(1);
            } else {
                this.dlg.ui.prompt.document.
                    documentElement.cancelDialog();
            }
        }).bind(this);

        if (this.action && this.action.accept ||
            !this.action && this.promptType == "alert") {
            ok();
        } else {
            cancel();
        }

        this.action = null;
        this.dlg = null;
    };


    obj.observe = function(subject, topic, data) {
        if (!(this.state == "playing" || this.state == "recording"))
            return;
        if (topic == "tabmodal-dialog-loaded") {
            this.tabmodal = true;
        } else if (topic == "common-dialog-loaded") {
            if (!this.actions.length && subject.Dialog.args.title == "iMacros")
                return;        
            
            
            
            const browser_xul = "chrome://browser/content/browser.xul";
            if (subject.opener && subject.opener.document.URL == browser_xul &&
                subject.Dialog.args.promptType != "promptUserAndPass")
                return;     

            this.tabmodal = false;
        }

        this.dlg = subject.Dialog;
        this.promptType = this.dlg.args.promptType == "promptUserAndPass" ?
            "login" : this.dlg.args.promptType;
        try  {
            if (this.state == "recording") {
                this.recordDialog();
            } else if (this.state == "playing") {
                this.replayDialog();
            }
        } catch(ex) {
            Components.utils.reportError(ex);
        }
    };

    return obj;
})().init();
